import json
import logging
import re

from django.contrib.auth import login, authenticate, logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render, redirect
from django import http
from django.urls import reverse
from django.views import View
from django_redis import get_redis_connection

from celery_tasks.email.tasks import send_email
from meiduo_mall.utils.views import LoginRequiredJsonMixin
from . import constants
from .models import User, Address
from meiduo_mall.utils.response_code import RETCODE
from .utils import generate_verify_email_url, check_verify_email_token

logger=logging.getLogger('django')
# 类视图
# 用户注册
class RegisterView(View):
    def get(self,request):
        return  render(request,'register.html')

    # 实现用户注册逻辑
    def post(self,request):
        # 1.接受参数-表单参数
        username=request.POST.get("user_name")
        password = request.POST.get("pwd")
        password2 = request.POST.get("cpwd")
        mobile = request.POST.get("phone")
        allow = request.POST.get("allow")
        sms_code_client=request.POST.get("msg_code")
        # 2.校验参数:前后端的校验需要分开，避免用户越过前端逻辑发起请求，要保证后端的安全，前后端的校验逻辑相同
        # 判断参数是否齐全
        if not all([username,password,password2,mobile,allow]):#列表中只要有个元素为空，就返回false
            return http.HttpResponseForbidden('缺少必传参数')
        # 判断用户名是否5-20个字符
        if  not re.match(r'^[a-zA-Z0-9_-]{5,20}$',username):
            return http.HttpResponseForbidden('请输入5-20个字符的用户名')
        # 判断密码是否8-20个字符
        if  not re.match(r'^[a-zA-Z0-9]{8,20}$',password):
            return http.HttpResponseForbidden('请输入8-20个字符的密码')
        # 判断两次输入的密码是否一致
        if password != password2:
            return http.HttpResponseForbidden('两次输入的密码不一致')
        # 判断手机号是否合法
        if not re.match(r'^1[3-9]\d{9}$',mobile):
            return http.HttpResponseForbidden('手机号不合法')
        # 校验短信验证码是否正确
        redis_conn = get_redis_connection('verify_code')
        sms_code_server = redis_conn.get('sms_%s'%mobile)
        if sms_code_server is None:
            return  render(request,'register.html',{'register_errmsg':'短信验证码已失效'})
        if sms_code_server.decode() != sms_code_client:
            return render(request, 'register.html', {'register_errmsg': '短信验证码错误'})
        # 判断用户是否勾选了协议
        if allow != 'on':
            return http.HttpResponseForbidden('请勾选协议')
        # 3.保存注册数据--重点
        try:
            user=User.objects.create_user(username=username,password=password,mobile=mobile)
        except Exception:
            return render(request,'register.html',{'register_msg':'注册失败'})

        # 实现状态保持
        login(request,user)
        # # 4.响应结果,重定向到首页
        # # return http.HttpResponse('注册成功，重定向到首页')
        # return redirect(reverse('contents:index'))
        response = redirect(reverse('contents:index'))
        # 设置cookie
        response.set_cookie('username', user.username, max_age=3600 * 24 * 14)
        # 4、响应结束:重定向到首页
        return response

# 判断用户名是否重复注册
class UsernameCountView(View):
    def get(self,request,username):
        '''
        :param request:
        :param username:
        :return: json
        '''
        count=User.objects.filter(username=username).count()
        return  http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok','count':count})

#判断手机号是否重复注册
class MobileCountView(View):
    def get(self,request,mobile):
        '''
        :param request:
        :param mobile: 手机号
        :return: json
        '''
        count=User.objects.filter(mobile=mobile).count()
        return  http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok','count':count})

# 用户登录
class LoginView(View):

    def get(self,request):
        # 获取登录界面
        return  render(request,'login.html')
    def post(self,request):
        # 1、接受参数
        username=request.POST.get('username')
        password=request.POST.get('pwd')
        remembered=request.POST.get('remembered')
        # 2、校验参数
        if not all([username,password]):
            return http.HttpResponseForbidden('缺少必传参数')
        # 判断用户名是否5-20个字符
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('请输入5-20个字符的用户名')
        # 判断密码是否8-20个字符
        if not re.match(r'^[a-zA-Z0-9]{8,20}$', password):
            return http.HttpResponseForbidden('请输入8-20个字符的密码')
        # 3、业务逻辑
        # 3.1 认证用户
        # user=User.objects.get(username=username)
        # user.check_password()
        user=authenticate(username=username,password=password)
        if user is None:
            return render(request,'login.html',{'account_errmsg':'账号或者密码错误'})
            # return http.JsonResponse({'account_errmsg':'账号或者密码错误'})
        # 3.2 状态保持
        login(request,user)
        # 使用remembered确定状态保持周期，实现记住用户
        if remembered != 'on':
            # 没有记住登录，状态保持在浏览器会话结束后就销毁
            request.session.set_expiry(0)
        else:
            # 记住记录，状态保持周期为3天,默认是2周
            request.session.set_expiry(60*60*24*3)
        # 4、响应结果
        # 先取出next
        next = request.GET.get('next')
        if next:
            # 重定向到next
            response=redirect(next)
        else:
            response=redirect(reverse('contents:index'))

        # 设置cookie
        response.set_cookie('username',user.username,max_age=3600*24*14)
        return response


# 退出登录
class LogoutView(View):
    def get(self,request):
        # 退出登录重定向到首页
        response = redirect(reverse('contents:index'))
        logout(request)
        response.delete_cookie('username')
        return response


# 用户中心
class InfoView(LoginRequiredMixin,View):
    def get(self,request):
        # if request.user.is_authenticated:
        #     return render(request,'user_center_info.html')
        # else:
        #     return render(request, reverse('users:login'))

        context={
            'username':request.user.username,
            'mobile':request.user.mobile,
            'email':request.user.email,
            'email_active':request.user.email_active

        }
        return render(request,'user_center_info.html',context)


# 添加邮箱
class EmailView(LoginRequiredJsonMixin,View):
    def put(self,request):
        # 接受参数
        json_str=request.body.decode()#body的类型为bytes
        json_dict=json.loads(json_str)
        try:
            email=json_dict.get('email')
            # 校验参数
            '''校验邮箱'''
            # 主逻辑：将用户传入的邮箱保存到用户数据库的email字段
            request.user.email=email
            request.user.save()

        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code':RETCODE.DBERR,'errmsg':'添加邮箱失败'})
        # 发送验证邮件
        verify_url=generate_verify_email_url(request.user)
        # 发邮件,一定要调用.delay
        send_email.delay(email, verify_url)
        # 返回数据
        return http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok'})


# 邮箱链接激活认证
class VerifyEmailView(View):
    def get(self,request):
        # 1、接受参数
        token=request.GET.get('token')#加密数据
        # 2、校验参数
        if not token:
            return  http.HttpResponseForbidden({'缺失token'})
        # 3、主逻辑
        # 3.1从token中提取user
        user=check_verify_email_token(token)
        if not user:
            return  http.HttpResponseForbidden('无效的token')
        try:
            user.email_active=True
            user.save()
        except Exception as e:
            logger.error(e)
            return http.HttpResponseServerError('激活邮箱失败')
        # 4、响应结果：重定向到用户中心
        return redirect(reverse('users:info'))

# 用户收货地址展示
class AddressView(LoginRequiredMixin,View):
    def get(self,request):
        # 查询地址
        login_user=request.user
        addresses=Address.objects.filter(user=login_user,is_deleted=False)
        # 将用户地址模型列表转字典列表，因为JsonResponse和Vue.js不认识模型列表，
        # 只有Django和Jinjia2模版引擎认识
        address_list=[]
        for address in addresses:
            address_dict={
                'id': address.id,
                'title': address.title,
                'receiver': address.receiver,
                'province': address.province.name,
                'city': address.city.name,
                'district': address.district.name,
                'place': address.place,
                'mobile': address.mobile,
                'tel': address.tel,
                'email': address.email,

            }
            address_list.append(address_dict)
        context={
            'default_address_id':login_user.default_address_id,
            'addresses':address_list

        }

        return  render(request,'user_center_site.html',context)

# 用户收货地址新增
class AddressCreateView(LoginRequiredJsonMixin,View):
    def post(self,request):
        # 判断用户地址是否超过上限
        # count=Address.objects.filter(user=request.user).count() #第一种写法
        count=request.user.addresses.count() #第二种写法，一查多
        if count >constants.USER_ADDRES_COUNTS_LIMIT:
            return http.JsonResponse({'code':RETCODE.THROTTLINGERR,'errmsg':'超出用户地址上限'})

        # 1.接受参数
        josn_str=request.body.decode()
        json_dict=json.loads(josn_str)
        receiver=json_dict.get('receiver')
        province_id=json_dict.get('province_id')
        city_id=json_dict.get('city_id')
        district_id=json_dict.get('district_id')
        place=json_dict.get('place')
        mobile=json_dict.get('mobile')
        tel=json_dict.get('tel')
        email=json_dict.get('email')
        # 2.校验参数
        # 3.主逻辑-保存数据
        try:
            address=Address.objects.create(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email,
            )
            # 判断是否有默认地址
            if not request.user.default_address:
                request.user.default_address=address
                request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code':RETCODE.DBERR,'errmsg':'新增地址失败'})

        # 构造新增地址字典数据
        address_dict={
            'id' : address.id,
            'title' : address.title,
            'receiver' : address.receiver,
            'province' : address.province.name,
            'city' : address.city.name,
            'district':address.district.name,
            'place' : address.place,
            'mobile' :address.mobile ,
            'tel' : address.tel ,
            'email' : address.email,
        }
        # 返回响应结果json
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '新增地址成功','address':address_dict})


# 用户收货地址更新和删除
class UpdatedDestoryAddressView(LoginRequiredJsonMixin,View):
    # 更新地址
    def put(self,request,address_id):

        # 1、接受参数
        josn_str = request.body.decode()
        json_dict = json.loads(josn_str)
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')
        # 2、校验参数
        # 3、主逻辑
        try:
            Address.objects.filter(id=address_id).update(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email,
            )
            address = Address.objects.get(id=address_id)
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '更新地址失败'})
        # 4、返回响应
        address_dict={
            'id' : address.id,
            'title' : address.title,
            'receiver' : address.receiver,
            'province' : address.province.name,
            'city' : address.city.name,
            'district':address.district.name,
            'place' : address.place,
            'mobile' :address.mobile ,
            'tel' : address.tel ,
            'email' : address.email,
        }
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '修改地址成功','address':address_dict})

    # 删除地址
    def delete(self,request,address_id):

        # 主体逻辑
        try:
            address=Address.objects.get(id=address_id)
            address.is_deleted=True
            address.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code':RETCODE.DBERR,'errmsg':'删除地址失败'})
        else:
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '删除地址成功'})

# 设置默认地址
class DefaultAddressView(LoginRequiredJsonMixin,View):
    def put(self,request,address_id):
        try:
            address=Address.objects.get(id=address_id)
            request.user.default_address=address
            request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '设置默认地址失败'})

        else:
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '设置地址成功'})

# 更新地址标题
class UpdateTitleAddressView(LoginRequiredJsonMixin,View):
    def put(self,request,address_id):
        json_str=request.body.decode()
        json_dict=json.loads(json_str)
        title=json_dict.get('title')
        if not title:
            return http.HttpResponseForbidden('没有title参数')
        try:
            address=Address.objects.get(id=address_id)
            address.title=title
            address.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '更新title失败'})
        else:
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '更新title成功'})



